`include "defines.v"

module RVCPU (
    input wire clock,
    input wire reset,

    // Advanced eXtensible Interface
    input  wire                              axi_aw_ready,
    output wire                              axi_aw_valid,
    output wire [`AXI_ADDR_WIDTH-1:0]        axi_aw_addr,
    output wire [2:0]                        axi_aw_prot,
    output wire [`AXI_ID_WIDTH+1:0]          axi_aw_id,
    output wire [`AXI_USER_WIDTH-1:0]        axi_aw_user,
    output wire [7:0]                        axi_aw_len,
    output wire [2:0]                        axi_aw_size,
    output wire [1:0]                        axi_aw_burst,
    output wire                              axi_aw_lock,
    output wire [3:0]                        axi_aw_cache,
    output wire [3:0]                        axi_aw_qos,
    output wire [3:0]                        axi_aw_region,

    input  wire                              axi_w_ready,
    output wire                              axi_w_valid,
    output wire [`AXI_DATA_WIDTH-1:0]        axi_w_data,
    output wire [`AXI_DATA_WIDTH/8-1:0]      axi_w_strb,
    output wire                              axi_w_last,
    output wire [`AXI_USER_WIDTH-1:0]        axi_w_user,
    
    output wire                              axi_b_ready,
    input  wire                              axi_b_valid,
    input  wire [1:0]                        axi_b_resp,
    input  wire [`AXI_ID_WIDTH+1:0]          axi_b_id,
    input  wire [`AXI_USER_WIDTH-1:0]        axi_b_user,

    input  wire                              axi_ar_ready,
    output wire                              axi_ar_valid,
    output wire [`AXI_ADDR_WIDTH-1:0]        axi_ar_addr,
    output wire [2:0]                        axi_ar_prot,
    output wire [`AXI_ID_WIDTH+1:0]          axi_ar_id,
    output wire [`AXI_USER_WIDTH-1:0]        axi_ar_user,
    output wire [7:0]                        axi_ar_len,
    output wire [2:0]                        axi_ar_size,
    output wire [1:0]                        axi_ar_burst,
    output wire                              axi_ar_lock,
    output wire [3:0]                        axi_ar_cache,
    output wire [3:0]                        axi_ar_qos,
    output wire [3:0]                        axi_ar_region,
    
    output wire                              axi_r_ready,
    input  wire                              axi_r_valid,
    input  wire [1:0]                        axi_r_resp,
    input  wire [`AXI_DATA_WIDTH-1:0]        axi_r_data,
    input  wire                              axi_r_last,
    input  wire [`AXI_ID_WIDTH+1:0]          axi_r_id,
    input  wire [`AXI_USER_WIDTH-1:0]        axi_r_user,


    //for sim
    output wire [3:0] stall,
    output wire flush,
    output wire trap,
    output wire [63: 0] gpr [31: 0],
    output wire RegWr,
    output wire [4:0] rd_addr,
    output wire [`XLEN-1:0] data_to_reg,
    output wire [63: 0] pc_addr,
    output wire mem_okay,
    output wire [`INSTLEN-1:0] inst,
    output wire inst_valid,
    output wire clint_skip,
    output wire bubble,

    //Machine Information Registers
    output reg [`MXLEN-1:0] mhartid,

    //Machine Trap Setup
    output reg [`MXLEN-1:0] mstatus,
    output reg [`MXLEN-1:0] mie,
    output reg [`MXLEN-1:0] mtvec,

    //Machine Trap Handling
    output reg [`MXLEN-1:0] mscratch,
    output reg [`MXLEN-1:0] mepc,
    output reg [`MXLEN-1:0] mcause,
    output reg [`MXLEN-1:0] mip,
 
    //Machine Counter/Timers
    output reg [`MXLEN-1:0] mcycle,
    output reg [`MXLEN-1:0] minstret
);
    //for sim
    assign RegWr = rd_w_en;
    assign rd_addr = rd_w_addr;
    assign data_to_reg = rd_w_data;

    //----------Regfile----------//
    wire                         rs1_r_en;
    wire [`REGFILE_ADDR_LEN-1:0] rs1_r_addr;
    wire [`XLEN-1:0]             rs1_r_data;
    wire                         rs2_r_en;
    wire [`REGFILE_ADDR_LEN-1:0] rs2_r_addr;
    wire [`XLEN-1:0]             rs2_r_data;
    wire                         rd_w_en;
    wire [`REGFILE_ADDR_LEN-1:0] rd_w_addr;
    wire [`XLEN-1:0]             rd_w_data;

    regfile regfile (
        .clock               (clock),
        .reset               (reset),

        .rs1_r_en            (rs1_r_en),
        .rs1_r_addr          (rs1_r_addr),
        .rs1_r_data          (rs1_r_data),

        .rs2_r_en            (rs2_r_en),
        .rs2_r_addr          (rs2_r_addr),
        .rs2_r_data          (rs2_r_data),

        .rd_w_en             (rd_w_en),
        .rd_w_addr           (rd_w_addr),
        .rd_w_data           (rd_w_data),
        .rf                  (gpr)
    );

    //----------Control and Status Register----------//
    wire                inst_fetched;
    wire                csr_r_en;
    wire [11: 0]        csr_r_addr;
    wire [`MXLEN-1:0]   csr_r_data;
    wire                csr_w_en;
    wire [11: 0]        csr_w_addr;
    wire [`MXLEN-1:0]   csr_w_data;
    wire                exception_jump_flag;
    wire [`BUSLEN-1:0]  exception_jump_addr;
    wire [ 5: 0]        mtimefreq;

    assign csr_r_addr = o_csr_w_addr_id;

    CSR CSR(
        .clock                           (clock),
        .reset                           (reset),

        .inst_fetched                    (inst_fetched),
        .flush                           (flush),
        .stall                           (stall),

        .inst_ecall                      (inst_ecall_mem),
        .inst_mret                       (inst_mret_mem),
        .intr                            (intr),
        .pc_valid                        (i_pc_valid_ex),
        .inst_jump_or_branch_taken_flag  (inst_jump_or_branch_taken_flag),
        .epc_ex                          (i_pc_ex),
        .epc_mem                         (inst_jump_or_branch_taken_addr),
        .exception_jump_flag             (exception_jump_flag),
        .exception_jump_addr             (exception_jump_addr),
        .mem_r_req                       (mem_r_req),
        .mem_w_req                       (mem_w_req),

        .csr_r_en                        (csr_r_en),
        .csr_r_addr                      (csr_r_addr),
        .csr_r_data                      (csr_r_data),

        .csr_w_en                        (csr_w_en),
        .csr_w_addr                      (csr_w_addr),
        .csr_w_data                      (csr_w_data),

        .mtimefreq                       (mtimefreq),

        .trap(trap),
        .mhartid(mhartid),
        .mstatus(mstatus),
        .mie(mie),
        .mtvec(mtvec),
        .mscratch(mscratch),
        .mepc(mepc),
        .mcause(mcause),
        .mip(mip),
        .mcycle(mcycle),
        .minstret(minstret)
    );

    //----------Pipeline----------//
    // Instruction Fetch
    wire [`BUSLEN-1:0] inst_jump_or_branch_taken_addr;
    IF_Stage Instruction_Fetch (
        .clock(clock),
        .reset(reset),

        .stall            (stall[0]),
        .flush            (flush),

        .exception_jump_flag                  (exception_jump_flag),
        .exception_jump_addr                  (exception_jump_addr),

        .inst_jump_or_branch_taken_flag       (inst_jump_or_branch_taken_flag),
        .inst_jump_or_branch_taken_addr       (inst_jump_or_branch_taken_addr),

        .inst                                 (o_instruction_if),
        .inst_fetched                         (inst_fetched),
        .pc                                   (o_pc_if),
        .pc_valid                             (o_pc_valid_if),

        .if_r_req                             (if_r_req),
        .if_r_okay                            (if_r_okay),
        .if_r_handshaked                      (if_r_handshaked),
        .if_data_read                         (if_data_read),
        .if_r_addr                            (if_r_addr),
        .if_r_size                            (if_r_size),
        .if_r_resp                            (if_r_response),

        .inst_valid(inst_valid)
    );

    //sim
    assign pc_addr = i_pc_id;
    assign inst = i_instruction_id;         //TODO

    // Instruction Decode

    ID_Stage Instruction_Decode (
        .pc_i                            (i_pc_id),
        .pc_o                            (o_pc_id),
        .pc_valid_i                      (i_pc_valid_id),
        .pc_valid_o                      (o_pc_valid_id),
        .inst                            (i_instruction_id),

        .forward_rs1_flag                (forward_rs1_flag),
        .forward_rs2_flag                (forward_rs2_flag),
        .forward_csr_flag                (forward_csr_flag),
        .forward_rs1_data                (forward_rs1_data),
        .forward_rs2_data                (forward_rs2_data), 
        .forward_csr_data                (forward_csr_data),

        .rs1_data_i                      (rs1_r_data),
        .rs2_data_i                      (rs2_r_data),
        .csr_data_i                      (csr_r_data),

        .regbus_A                        (o_regbus_A_id),
        .regbus_B                        (o_regbus_B_id),
        .imm                             (o_imm_id),

        .ALU_oprend_A_src                (o_ALU_oprend_A_src_id),
        .ALU_oprend_B_src                (o_ALU_oprend_B_src_id),
        .ALU_op                          (o_ALU_op_id),
        .ALU_out_ext_type                (o_ALU_out_ext_type_id),

        .rs1_r_en                        (rs1_r_en),
        .rs1_r_addr                      (rs1_r_addr),
        .rs2_r_en                        (rs2_r_en),
        .rs2_r_addr                      (rs2_r_addr),

        .rd_w_en                         (o_rd_w_en_id),
        .rd_w_src                        (o_rd_w_src_id),
        .rd_w_addr                       (o_rd_w_addr_id),

        .csr_r_en                        (csr_r_en),
        .csr_w_en                        (o_csr_w_en_id),
        .csr_rw_addr                     (o_csr_w_addr_id),

        .mem_r_en                        (o_mem_r_en_id),
        .mem_r_ext_type                  (o_mem_r_ext_type_id),
        .mem_w_en                        (o_mem_w_en_id),
        .mem_w_size                      (o_mem_w_size_id),

        .adder_src                       (o_adder_src_id),
        .inst_jump                       (o_inst_jump_id),
        .inst_branch_type                (o_inst_branch_type_id),

        .is_system_inst                  (o_is_system_inst_id),
        .inst_ecall                      (o_inst_ecall_id),
        .inst_mret                       (o_inst_mret_id),
        .inst_fencei                     (inst_fencei),
        .inst_wfi                        (inst_wfi)
    );

    // Execute
    wire pc_valid;

    EX_Stage Execute (
        .pc_i                       (i_pc_ex),
        .pc_valid_i                 (i_pc_valid_ex),
        .pc_o                       (o_pc_ex),
        .pc_valid_o                 (pc_valid),

        .regbus_A                   (i_regbus_A_ex),
        .regbus_B                   (i_regbus_B_ex),
        .imm                        (i_imm_ex),
        .ALU_out                    (o_ALU_out_ex),
        .psw_flags                  (o_psw_flags_ex),

        .ALU_oprend_A_src           (i_ALU_oprend_A_src_ex),
        .ALU_oprend_B_src           (i_ALU_oprend_B_src_ex),
        .ALU_op                     (i_ALU_op_ex),
        .ALU_out_ext_type           (i_ALU_out_ext_type_ex),

        .mem_r_en_i                 (i_mem_r_en_ex),
        .mem_r_ext_type_i           (i_mem_r_ext_type_ex),
        .mem_w_en_i                 (i_mem_w_en_ex),
        .mem_w_size_i               (i_mem_w_size_ex),
        .mem_r_en_o                 (o_mem_r_en_ex),
        .mem_r_ext_type_o           (o_mem_r_ext_type_ex),
        .mem_w_en_o                 (o_mem_w_en_ex),
        .mem_w_size_o               (o_mem_w_size_ex),
        .regbus_B_o                 (o_regbus_B_ex),

        .rd_w_addr_i                (i_rd_w_addr_ex),
        .rd_w_en_i                  (i_rd_w_en_ex),
        .rd_w_src_i                 (i_rd_w_src_ex),
        .rd_w_addr_o                (o_rd_w_addr_ex),
        .rd_w_en_o                  (o_rd_w_en_ex),
        .rd_w_src_o                 (o_rd_w_src_ex),
        .csr_w_en_i                 (i_csr_w_en_ex),
        .csr_w_addr_i               (i_csr_w_addr_ex),
        .csr_w_en_o                 (o_csr_w_en_ex),
        .csr_w_addr_o               (o_csr_w_addr_ex),

        .adder_src                  (i_adder_src_ex),
        .inst_jump_i                (i_inst_jump_ex),
        .inst_branch_type_i         (i_inst_branch_type_ex),
        .inst_jump_o                (o_inst_jump_ex),
        .inst_branch_type_o         (o_inst_branch_type_ex),

        .is_system_inst_i           (i_is_system_inst_ex),
        .is_system_inst_o           (o_is_system_inst_ex),
        .inst_ecall_i               (i_inst_ecall_ex),
        .inst_mret_i                (i_inst_mret_ex),
        .inst_ecall_o               (o_inst_ecall_ex),
        .inst_mret_o                (o_inst_mret_ex)
    );

    // Memory
    wire inst_ecall_mem;
    wire inst_mret_mem;

    MEM_Stage Memory (
        .inst_jump                             (i_inst_jump_mem),
        .inst_branch_type                      (i_inst_branch_type_mem),
        .psw_flags                             (i_psw_flags_mem),
        .branch_target_pc_i                    (i_branch_target_pc_mem),
        .inst_jump_or_branch_taken_flag        (inst_jump_or_branch_taken_flag),
        .branch_target_pc_o                    (inst_jump_or_branch_taken_addr),

        .rd_w_addr_i                           (i_rd_w_addr_mem),
        .rd_w_en_i                             (i_rd_w_en_mem),
        .rd_w_src_i                            (i_rd_w_src_mem),
        .rd_w_addr_o                           (o_rd_w_addr_mem),
        .rd_w_en_o                             (o_rd_w_en_mem),
        .rd_w_src_o                            (o_rd_w_src_mem),
        .csr_w_en_i                            (i_csr_w_en_mem),
        .csr_w_addr_i                          (i_csr_w_addr_mem),
        .csr_w_en_o                            (o_csr_w_en_mem),
        .csr_w_addr_o                          (o_csr_w_addr_mem),

        .mem_r_en                              (i_mem_r_en_mem),
        .mem_r_ext_type_i                      (i_mem_r_ext_type_mem),
        .mem_w_en                              (i_mem_w_en_mem),
        .mem_w_size_i                          (i_mem_w_size_mem),
        .ALU_out_i                             (i_ALU_out_mem),
        .regbus_B_i                            (i_regbus_B_mem),
        .mem_r_ext_type_o                      (o_mem_r_ext_type_mem),
        .regbus_C                              (o_regbus_C_mem),
        .regbus_D                              (o_regbus_D_mem),
        .mem_stall_req                         (mem_stall_req),

        .is_system_inst                        (i_is_system_inst_mem),
        .inst_ecall_i                          (i_inst_ecall_mem),
        .inst_mret_i                           (i_inst_mret_mem),
        .inst_ecall_o                          (inst_ecall_mem),
        .inst_mret_o                           (inst_mret_mem),

        .mem_okay                              (mem_okay),  //todo

        .mem_r_req              (mem_r_req),
        .mem_r_handshaked       (mem_r_handshaked),
        .mem_r_okay             (mem_r_okay),
        .mem_data_read          (mem_data_read),
        .mem_r_addr             (mem_r_addr),
        .mem_r_size             (mem_r_size),
        .mem_r_resp             (mem_r_response),
        .mem_w_req              (mem_w_req),
        .mem_w_okay             (mem_w_okay),
        .mem_data_write         (mem_data_write),
        .mem_w_addr             (mem_w_addr),
        .mem_w_size             (mem_w_size),
        .mem_w_resp             (mem_w_response)
    );

    // Write Back
    WB_Stage Write_Back (
        .regbus_C               (i_regbus_C_wb),
        .regbus_D               (i_regbus_D_wb),
        .mem_r_ext_type         (i_mem_r_ext_type_wb),
        .rd_w_addr_i            (i_rd_w_addr_wb),
        .rd_w_en_i              (i_rd_w_en_wb),
        .rd_w_src               (i_rd_w_src_wb),
        .rd_w_addr_o            (rd_w_addr),
        .rd_w_en_o              (rd_w_en),
        .rd_w_data              (rd_w_data),
        .csr_w_en_i             (i_csr_w_en_wb),
        .csr_w_addr_i           (i_csr_w_addr_wb),
        .csr_w_en_o             (csr_w_en),
        .csr_w_addr_o           (csr_w_addr),
        .csr_data               (csr_w_data)
    );

    //----------Pipeline Regs----------//
    wire                         o_pc_valid_if;
    wire [`BUSLEN-1:0]           o_pc_if;
    wire [`INSTLEN-1:0]          o_instruction_if;
    wire                         i_pc_valid_id;
    wire [`BUSLEN-1:0]           i_pc_id;
    wire [`INSTLEN-1:0]          i_instruction_id;

    wire [`XLEN-1:0]             o_regbus_A_id;
    wire [`XLEN-1:0]             o_regbus_B_id;
    wire [`XLEN-1:0]             o_imm_id;
    wire [ 1: 0]                 o_ALU_oprend_A_src_id;
    wire [ 1: 0]                 o_ALU_oprend_B_src_id;
    wire [ 2: 0]                 o_ALU_op_id;
    wire [ 2: 0]                 o_ALU_out_ext_type_id;
    wire                         o_adder_src_id;
    wire [`BUSLEN-1:0]           o_pc_id;
    wire                         o_pc_valid_id;
    wire                         o_mem_r_en_id;
    wire [ 2: 0]                 o_mem_r_ext_type_id;
    wire                         o_mem_w_en_id;
    wire [ 1: 0]                 o_mem_w_size_id;
    wire                         o_inst_jump_id;
    wire [ 2: 0]                 o_inst_branch_type_id;
    wire                         o_is_system_inst_id;
    wire                         o_inst_ecall_id;
    wire                         o_inst_mret_id;
    wire                         o_rd_w_en_id;
    wire                         o_rd_w_src_id;
    wire [`REGFILE_ADDR_LEN-1:0] o_rd_w_addr_id;
    wire                         o_csr_w_en_id;
    wire [`CSR_ADDR_LEN-1:0]     o_csr_w_addr_id;
    wire [`XLEN-1:0]             i_regbus_A_ex;
    wire [`XLEN-1:0]             i_regbus_B_ex;
    wire [`XLEN-1:0]             i_imm_ex;
    wire [ 1: 0]                 i_ALU_oprend_A_src_ex;
    wire [ 1: 0]                 i_ALU_oprend_B_src_ex;
    wire [ 2: 0]                 i_ALU_op_ex;
    wire [ 2: 0]                 i_ALU_out_ext_type_ex;
    wire                         i_adder_src_ex;
    wire [`BUSLEN-1:0]           i_pc_ex;
    wire                         i_pc_valid_ex;
    wire                         i_mem_r_en_ex;
    wire [ 2: 0]                 i_mem_r_ext_type_ex;
    wire                         i_mem_w_en_ex;
    wire [ 1: 0]                 i_mem_w_size_ex;
    wire                         i_inst_jump_ex;
    wire [ 2: 0]                 i_inst_branch_type_ex;
    wire                         i_is_system_inst_ex;
    wire                         i_inst_ecall_ex;
    wire                         i_inst_mret_ex;
    wire                         i_rd_w_en_ex;
    wire                         i_rd_w_src_ex;
    wire [`REGFILE_ADDR_LEN-1:0] i_rd_w_addr_ex;
    wire                         i_csr_w_en_ex;
    wire [`CSR_ADDR_LEN-1:0]     i_csr_w_addr_ex;

    wire [`BUSLEN-1:0]           o_pc_ex;
    wire [`BUSLEN-1:0]           o_ALU_out_ex;
    wire [ 3: 0]                 o_psw_flags_ex;
    wire                         o_mem_r_en_ex;
    wire [ 2: 0]                 o_mem_r_ext_type_ex;
    wire                         o_mem_w_en_ex;
    wire [ 1: 0]                 o_mem_w_size_ex;
    wire [`BUSLEN-1:0]           o_regbus_B_ex;
    wire [`REGFILE_ADDR_LEN-1:0] o_rd_w_addr_ex;
    wire                         o_rd_w_en_ex;
    wire                         o_rd_w_src_ex;
    wire                         o_csr_w_en_ex;
    wire [`CSR_ADDR_LEN-1:0]     o_csr_w_addr_ex;
    wire                         o_inst_jump_ex;
    wire [ 2: 0]                 o_inst_branch_type_ex;
    wire                         o_is_system_inst_ex;
    wire                         o_inst_ecall_ex;
    wire                         o_inst_mret_ex;
    wire [`BUSLEN-1:0]           i_branch_target_pc_mem;
    wire [`BUSLEN-1:0]           i_ALU_out_mem;
    wire [ 3: 0]                 i_psw_flags_mem;
    wire                         i_mem_r_en_mem;
    wire [ 2: 0]                 i_mem_r_ext_type_mem;
    wire                         i_mem_w_en_mem;
    wire [ 1: 0]                 i_mem_w_size_mem;
    wire [`BUSLEN-1:0]           i_regbus_B_mem;
    wire [`REGFILE_ADDR_LEN-1:0] i_rd_w_addr_mem;
    wire                         i_rd_w_en_mem;
    wire                         i_rd_w_src_mem;
    wire                         i_csr_w_en_mem;
    wire [`CSR_ADDR_LEN-1:0]     i_csr_w_addr_mem;
    wire                         i_inst_jump_mem;
    wire [ 2: 0]                 i_inst_branch_type_mem;
    wire                         i_is_system_inst_mem;
    wire                         i_inst_ecall_mem;
    wire                         i_inst_mret_mem;

    wire [`REGFILE_ADDR_LEN-1:0] o_rd_w_addr_mem;
    wire                         o_rd_w_en_mem;
    wire                         o_rd_w_src_mem;
    wire                         o_csr_w_en_mem;
    wire [`CSR_ADDR_LEN-1:0]     o_csr_w_addr_mem;
    wire [ 2: 0]                 o_mem_r_ext_type_mem;
    wire [`BUSLEN-1:0]           o_regbus_C_mem;
    wire [`BUSLEN-1:0]           o_regbus_D_mem;
    wire [`REGFILE_ADDR_LEN-1:0] i_rd_w_addr_wb;
    wire                         i_rd_w_en_wb;
    wire                         i_rd_w_src_wb;
    wire                         i_csr_w_en_wb;
    wire [`CSR_ADDR_LEN-1:0]     i_csr_w_addr_wb;
    wire [ 2: 0]                 i_mem_r_ext_type_wb;
    wire [`BUSLEN-1:0]           i_regbus_C_wb;
    wire [`BUSLEN-1:0]           i_regbus_D_wb;

    pipeline_regs pipeline_regs (
        .clock(clock),
        .reset(reset),

        .bubble(bubble),
        .flush(flush),
        .stall(stall),

        .o_pc_valid_if                 (o_pc_valid_if),
        .o_pc_if                       (o_pc_if),
        .o_instruction_if              (o_instruction_if),
        .i_pc_valid_id                 (i_pc_valid_id),
        .i_pc_id                       (i_pc_id),
        .i_instruction_id              (i_instruction_id),

        .o_regbus_A_id                 (o_regbus_A_id),
        .o_regbus_B_id                 (o_regbus_B_id),
        .o_imm_id                      (o_imm_id),
        .o_ALU_oprend_A_src_id         (o_ALU_oprend_A_src_id),
        .o_ALU_oprend_B_src_id         (o_ALU_oprend_B_src_id),
        .o_ALU_op_id                   (o_ALU_op_id),
        .o_ALU_out_ext_type_id         (o_ALU_out_ext_type_id),
        .o_adder_src_id                (o_adder_src_id),
        .o_pc_id                       (o_pc_id),
        .o_pc_valid_id                 (o_pc_valid_id),
        .o_mem_r_en_id                 (o_mem_r_en_id),
        .o_mem_r_ext_type_id           (o_mem_r_ext_type_id),
        .o_mem_w_en_id                 (o_mem_w_en_id),
        .o_mem_w_size_id               (o_mem_w_size_id),
        .o_inst_jump_id                (o_inst_jump_id),
        .o_inst_branch_type_id         (o_inst_branch_type_id),
        .o_is_system_inst_id           (o_is_system_inst_id),
        .o_inst_ecall_id               (o_inst_ecall_id),
        .o_inst_mret_id                (o_inst_mret_id),
        .o_rd_w_en_id                  (o_rd_w_en_id),
        .o_rd_w_src_id                 (o_rd_w_src_id),
        .o_rd_w_addr_id                (o_rd_w_addr_id),
        .o_csr_w_en_id                 (o_csr_w_en_id),
        .o_csr_w_addr_id               (o_csr_w_addr_id),        
        .i_regbus_A_ex                 (i_regbus_A_ex),
        .i_regbus_B_ex                 (i_regbus_B_ex),
        .i_imm_ex                      (i_imm_ex),
        .i_ALU_oprend_A_src_ex         (i_ALU_oprend_A_src_ex),
        .i_ALU_oprend_B_src_ex         (i_ALU_oprend_B_src_ex),
        .i_ALU_op_ex                   (i_ALU_op_ex),
        .i_ALU_out_ext_type_ex         (i_ALU_out_ext_type_ex),
        .i_adder_src_ex                (i_adder_src_ex),
        .i_pc_ex                       (i_pc_ex),
        .i_pc_valid_ex                 (i_pc_valid_ex),
        .i_mem_r_en_ex                 (i_mem_r_en_ex),
        .i_mem_r_ext_type_ex           (i_mem_r_ext_type_ex),
        .i_mem_w_en_ex                 (i_mem_w_en_ex),
        .i_mem_w_size_ex               (i_mem_w_size_ex),
        .i_inst_jump_ex                (i_inst_jump_ex),
        .i_inst_branch_type_ex         (i_inst_branch_type_ex),
        .i_is_system_inst_ex           (i_is_system_inst_ex),
        .i_inst_ecall_ex               (i_inst_ecall_ex),
        .i_inst_mret_ex                (i_inst_mret_ex),
        .i_rd_w_en_ex                  (i_rd_w_en_ex),
        .i_rd_w_src_ex                 (i_rd_w_src_ex),
        .i_rd_w_addr_ex                (i_rd_w_addr_ex),
        .i_csr_w_en_ex                 (i_csr_w_en_ex),
        .i_csr_w_addr_ex               (i_csr_w_addr_ex),

        .o_pc_ex                       (o_pc_ex),
        .o_ALU_out_ex                  (o_ALU_out_ex),
        .o_psw_flags_ex                (o_psw_flags_ex),
        .o_mem_r_en_ex                 (o_mem_r_en_ex),
        .o_mem_r_ext_type_ex           (o_mem_r_ext_type_ex),
        .o_mem_w_en_ex                 (o_mem_w_en_ex),
        .o_mem_w_size_ex               (o_mem_w_size_ex),
        .o_regbus_B_ex                 (o_regbus_B_ex),
        .o_rd_w_addr_ex                (o_rd_w_addr_ex),
        .o_rd_w_en_ex                  (o_rd_w_en_ex),
        .o_rd_w_src_ex                 (o_rd_w_src_ex),
        .o_csr_w_en_ex                 (o_csr_w_en_ex),
        .o_csr_w_addr_ex               (o_csr_w_addr_ex),
        .o_inst_jump_ex                (o_inst_jump_ex),
        .o_inst_branch_type_ex         (o_inst_branch_type_ex),
        .o_is_system_inst_ex           (o_is_system_inst_ex),
        .o_inst_ecall_ex               (o_inst_ecall_ex),
        .o_inst_mret_ex                (o_inst_mret_ex),
        .i_branch_target_pc_mem        (i_branch_target_pc_mem),
        .i_ALU_out_mem                 (i_ALU_out_mem),
        .i_psw_flags_mem               (i_psw_flags_mem),
        .i_mem_r_en_mem                (i_mem_r_en_mem),
        .i_mem_r_ext_type_mem          (i_mem_r_ext_type_mem),
        .i_mem_w_en_mem                (i_mem_w_en_mem),
        .i_mem_w_size_mem              (i_mem_w_size_mem),
        .i_regbus_B_mem                (i_regbus_B_mem),
        .i_rd_w_addr_mem               (i_rd_w_addr_mem),
        .i_rd_w_en_mem                 (i_rd_w_en_mem),
        .i_rd_w_src_mem                (i_rd_w_src_mem),
        .i_csr_w_en_mem                (i_csr_w_en_mem),
        .i_csr_w_addr_mem              (i_csr_w_addr_mem),
        .i_inst_jump_mem               (i_inst_jump_mem),
        .i_inst_branch_type_mem        (i_inst_branch_type_mem),
        .i_is_system_inst_mem          (i_is_system_inst_mem),
        .i_inst_ecall_mem              (i_inst_ecall_mem),
        .i_inst_mret_mem               (i_inst_mret_mem),

        .o_rd_w_addr_mem               (o_rd_w_addr_mem),
        .o_rd_w_en_mem                 (o_rd_w_en_mem),
        .o_rd_w_src_mem                (o_rd_w_src_mem),
        .o_csr_w_en_mem                (o_csr_w_en_mem),
        .o_csr_w_addr_mem              (o_csr_w_addr_mem),
        .o_mem_r_ext_type_mem          (o_mem_r_ext_type_mem),
        .o_regbus_C_mem                (o_regbus_C_mem),
        .o_regbus_D_mem                (o_regbus_D_mem),
        .i_rd_w_addr_wb                (i_rd_w_addr_wb),
        .i_rd_w_en_wb                  (i_rd_w_en_wb),
        .i_rd_w_src_wb                 (i_rd_w_src_wb),
        .i_csr_w_en_wb                 (i_csr_w_en_wb),
        .i_csr_w_addr_wb               (i_csr_w_addr_wb),
        .i_mem_r_ext_type_wb           (i_mem_r_ext_type_wb),
        .i_regbus_C_wb                 (i_regbus_C_wb),
        .i_regbus_D_wb                 (i_regbus_D_wb)
    );

    //---------- Hazard Detection ----------//
    wire                mem_stall_req;
    //wire [3:0] stall;
    wire                inst_jump_or_branch_taken_flag;
    //wire flush;
    wire inst_fencei;
    wire inst_wfi;
    //wire bubble;

    Hazard_Detection Hazard_Detection(
        .rs1_addr                         (rs1_r_addr),
        .rs2_addr                         (rs2_r_addr),
        .rd_addr_ex                       (o_rd_w_addr_ex),
        .rd_addr_mem                      (o_rd_w_addr_mem),
        .rd_w_en_ex                       (o_rd_w_en_ex),
        .csr_w_en_ex                      (o_csr_w_en_ex),
        .rd_w_src_ex                      (o_rd_w_src_ex),
        .rd_w_src_mem                     (o_rd_w_src_mem),
        .mem_stall_req                    (mem_stall_req),
        .inst_fencei                      (inst_fencei),
        .inst_wfi                         (inst_wfi),
        .stall                            (stall),
        .inst_jump_or_branch_taken_flag   (inst_jump_or_branch_taken_flag),
        .exception_jump_flag              (exception_jump_flag),
        .flush                            (flush),
        .bubble                           (bubble)
    );

    //---------- Forwarding ----------//
    wire forward_rs1_flag;
    wire forward_rs2_flag;
    wire forward_csr_flag;

    wire [`XLEN-1:0]  forward_rs1_data;
    wire [`XLEN-1:0]  forward_rs2_data;
    wire [`MXLEN-1:0] forward_csr_data;

    Forwarding Forwarding(
        .rs1_r_addr                  (rs1_r_addr),
        .rs2_r_addr                  (rs2_r_addr),
        .csr_r_addr                  (csr_r_addr),

        .rd_w_addr_ex                (o_rd_w_addr_ex),
        .rd_w_addr_mem               (o_rd_w_addr_mem),
        .rd_w_addr_wb                (rd_w_addr),
        .csr_w_addr_ex               (o_csr_w_addr_ex),
        .csr_w_addr_mem              (o_csr_w_addr_mem),
        .csr_w_addr_wb               (csr_w_addr),

        .rd_w_en_ex                  (o_rd_w_en_ex),
        .rd_w_en_mem                 (o_rd_w_en_mem),
        .rd_w_en_wb                  (rd_w_en),
        .rd_w_src_ex                 (o_rd_w_src_ex),
        .rd_w_src_mem                (o_rd_w_src_mem),
        .csr_w_en_ex                 (o_csr_w_en_ex),
        .csr_w_en_mem                (o_csr_w_en_mem),
        .csr_w_en_wb                 (csr_w_en),
        .forward_rs1_flag            (forward_rs1_flag),
        .forward_rs2_flag            (forward_rs2_flag),
        .forward_csr_flag            (forward_csr_flag),

        .rd_w_data_ex                (o_ALU_out_ex),
        .rd_w_data_mem               (o_regbus_D_mem),
        .rd_w_data_wb                (rd_w_data),
        .csr_w_data_ex               (o_ALU_out_ex),
        .csr_w_data_mem              (o_regbus_C_mem),
        .csr_w_data_wb               (csr_w_data),
        .forward_rs1_data            (forward_rs1_data),
        .forward_rs2_data            (forward_rs2_data),
        .forward_csr_data            (forward_csr_data)
    );

    //---------- Core-local Interrupter ----------//
    wire intr;
    wire                                clint_aw_ready;
    wire                                clint_aw_valid;
    wire [`AXI_ADDR_WIDTH-1:0]          clint_aw_addr;
    wire [2:0]                          clint_aw_prot;
    wire [`AXI_ID_WIDTH+1:0]            clint_aw_id;
    wire [`AXI_USER_WIDTH-1:0]          clint_aw_user;
    wire [7:0]                          clint_aw_len;
    wire [2:0]                          clint_aw_size;
    wire [1:0]                          clint_aw_burst;
    wire                                clint_aw_lock;
    wire [3:0]                          clint_aw_cache;
    wire [3:0]                          clint_aw_qos;
    wire [3:0]                          clint_aw_region;
    wire                                clint_w_ready;
    wire                                clint_w_valid;
    wire [`AXI_DATA_WIDTH-1:0]          clint_w_data;
    wire [`AXI_DATA_WIDTH/8-1:0]        clint_w_strb;
    wire                                clint_w_last;
    wire [`AXI_USER_WIDTH-1:0]          clint_w_user;
    wire                                clint_b_ready;
    wire                                clint_b_valid;
    wire [1:0]                          clint_b_resp;
    wire [`AXI_ID_WIDTH+1:0]            clint_b_id;
    wire [`AXI_USER_WIDTH-1:0]          clint_b_user;
    wire                                clint_ar_ready;
    wire                                clint_ar_valid;
    wire [`AXI_ADDR_WIDTH-1:0]          clint_ar_addr;
    wire [2:0]                          clint_ar_prot;
    wire [`AXI_ID_WIDTH+1:0]            clint_ar_id;
    wire [`AXI_USER_WIDTH-1:0]          clint_ar_user;
    wire [7:0]                          clint_ar_len;
    wire [2:0]                          clint_ar_size;
    wire [1:0]                          clint_ar_burst;
    wire                                clint_ar_lock;
    wire [3:0]                          clint_ar_cache;
    wire [3:0]                          clint_ar_qos;
    wire [3:0]                          clint_ar_region;
    wire                                clint_r_ready;
    wire                                clint_r_valid;
    wire [1:0]                          clint_r_resp;
    wire [`AXI_DATA_WIDTH-1:0]          clint_r_data;
    wire                                clint_r_last;
    wire [`AXI_ID_WIDTH+1:0]            clint_r_id;
    wire [`AXI_USER_WIDTH-1:0]          clint_r_user;

    clint clint (
        .clock            (clock),
        .reset_n          (~reset),

        .intr             (intr),
        .mtimefreq        (mtimefreq),

        .clint_aw_ready   (clint_aw_ready),
        .clint_aw_valid   (clint_aw_valid),
        .clint_aw_addr    (clint_aw_addr),
        .clint_aw_prot    (clint_aw_prot),
        .clint_aw_id      (clint_aw_id),
        .clint_aw_user    (clint_aw_user),
        .clint_aw_len     (clint_aw_len),
        .clint_aw_size    (clint_aw_size),
        .clint_aw_burst   (clint_aw_burst),
        .clint_aw_lock    (clint_aw_lock),
        .clint_aw_cache   (clint_aw_cache),
        .clint_aw_qos     (clint_aw_qos),
        .clint_aw_region  (clint_aw_region),

        .clint_w_ready    (clint_w_ready),
        .clint_w_valid    (clint_w_valid),
        .clint_w_data     (clint_w_data),
        .clint_w_strb     (clint_w_strb),
        .clint_w_last     (clint_w_last),
        .clint_w_user     (clint_w_user),

        .clint_b_ready    (clint_b_ready),
        .clint_b_valid    (clint_b_valid),
        .clint_b_resp     (clint_b_resp),
        .clint_b_id       (clint_b_id),
        .clint_b_user     (clint_b_user),

        .clint_ar_ready   (clint_ar_ready),
        .clint_ar_valid   (clint_ar_valid),
        .clint_ar_addr    (clint_ar_addr),
        .clint_ar_prot    (clint_ar_prot),
        .clint_ar_id      (clint_ar_id),
        .clint_ar_user    (clint_ar_user),
        .clint_ar_len     (clint_ar_len),
        .clint_ar_size    (clint_ar_size),
        .clint_ar_burst   (clint_ar_burst),
        .clint_ar_lock    (clint_ar_lock),
        .clint_ar_cache   (clint_ar_cache),
        .clint_ar_qos     (clint_ar_qos),
        .clint_ar_region  (clint_ar_region),

        .clint_r_ready    (clint_r_ready),
        .clint_r_valid    (clint_r_valid),
        .clint_r_resp     (clint_r_resp),
        .clint_r_data     (clint_r_data),
        .clint_r_last     (clint_r_last),
        .clint_r_id       (clint_r_id),
        .clint_r_user     (clint_r_user),

        .clint_skip       (clint_skip)             //todo
    );

    //---------- AXI Interconnect ----------//
    wire                               if_r_req;
    wire                               if_r_okay;
    wire                               if_r_handshaked;
    wire [`AXI_DATA_WIDTH-1:0]         if_data_read;
    wire [`AXI_ADDR_WIDTH-1:0]         if_r_addr;
    wire [ 1: 0]                       if_r_size;
    wire [ 1: 0]                       if_r_response;

    wire                               if_aw_ready;
    wire                               if_aw_valid;
    wire [`AXI_ADDR_WIDTH-1:0]         if_aw_addr;
    wire [ 2: 0]                       if_aw_prot;
    wire [`AXI_ID_WIDTH-1:0]           if_aw_id;
    wire [`AXI_USER_WIDTH-1:0]         if_aw_user;
    wire [ 7: 0]                       if_aw_len;
    wire [ 2: 0]                       if_aw_size;
    wire [ 1: 0]                       if_aw_burst;
    wire                               if_aw_lock;
    wire [ 3: 0]                       if_aw_cache;
    wire [ 3: 0]                       if_aw_qos;
    wire [ 3: 0]                       if_aw_region;

    wire                               if_w_ready;
    wire                               if_w_valid;
    wire [`AXI_DATA_WIDTH-1:0]         if_w_data;
    wire [`AXI_DATA_WIDTH/8-1:0]       if_w_strb;
    wire                               if_w_last;
    wire [`AXI_USER_WIDTH-1:0]         if_w_user;

    wire                               if_b_ready;
    wire                               if_b_valid;
    wire [ 1: 0]                       if_b_resp;
    wire [`AXI_ID_WIDTH-1:0]           if_b_id;
    wire [`AXI_USER_WIDTH-1:0]         if_b_user;

    wire                               if_ar_ready;
    wire                               if_ar_valid;
    wire [`AXI_ADDR_WIDTH-1:0]         if_ar_addr;
    wire [ 2: 0]                       if_ar_prot;
    wire [`AXI_ID_WIDTH-1:0]           if_ar_id;
    wire [`AXI_USER_WIDTH-1:0]         if_ar_user;
    wire [ 7: 0]                       if_ar_len;
    wire [ 2: 0]                       if_ar_size;
    wire [ 1: 0]                       if_ar_burst;
    wire                               if_ar_lock;
    wire [ 3: 0]                       if_ar_cache;
    wire [ 3: 0]                       if_ar_qos;
    wire [ 3: 0]                       if_ar_region;

    wire                               if_r_ready;
    wire                               if_r_valid;
    wire [ 1: 0]                       if_r_resp;
    wire [`AXI_DATA_WIDTH-1:0]         if_r_data;
    wire                               if_r_last;
    wire [`AXI_ID_WIDTH-1:0]           if_r_id;
    wire [`AXI_USER_WIDTH-1:0]         if_r_user;

    axi_rw # (
        .AXI_ID(0)
    ) if_axi_rw (
        .clock            (clock),
        .reset_n          (~reset),

        .r_req            (if_r_req),
        .r_handshaked     (if_r_handshaked),
        .r_okay           (if_r_okay),
        .data_read        (if_data_read),
        .r_addr           (if_r_addr),
        .r_size           (if_r_size),
        .r_resp           (if_r_response),

        .w_req            (),
        .w_okay           (),
        .data_write       (),
        .w_addr           (),
        .w_size           (),
        .w_resp           (),

        .axi_aw_ready_i   (if_aw_ready),
        .axi_aw_valid_o   (if_aw_valid),
        .axi_aw_addr_o    (if_aw_addr),
        .axi_aw_prot_o    (if_aw_prot),
        .axi_aw_id_o      (if_aw_id),
        .axi_aw_user_o    (if_aw_user),
        .axi_aw_len_o     (if_aw_len),
        .axi_aw_size_o    (if_aw_size),
        .axi_aw_burst_o   (if_aw_burst),
        .axi_aw_lock_o    (if_aw_lock),
        .axi_aw_cache_o   (if_aw_cache),
        .axi_aw_qos_o     (if_aw_qos),
        .axi_aw_region_o  (if_aw_region),

        .axi_w_ready_i    (if_w_ready),
        .axi_w_valid_o    (if_w_valid),
        .axi_w_data_o     (if_w_data),
        .axi_w_strb_o     (if_w_strb),
        .axi_w_last_o     (if_w_last),
        .axi_w_user_o     (if_w_user),

        .axi_b_ready_o    (if_b_ready),
        .axi_b_valid_i    (if_b_valid),
        .axi_b_resp_i     (if_b_resp),
        .axi_b_id_i       (if_b_id),
        .axi_b_user_i     (if_b_user),

        .axi_ar_ready_i   (if_ar_ready),
        .axi_ar_valid_o   (if_ar_valid),
        .axi_ar_addr_o    (if_ar_addr),
        .axi_ar_prot_o    (if_ar_prot),
        .axi_ar_id_o      (if_ar_id),
        .axi_ar_user_o    (if_ar_user),
        .axi_ar_len_o     (if_ar_len),
        .axi_ar_size_o    (if_ar_size),
        .axi_ar_burst_o   (if_ar_burst),
        .axi_ar_lock_o    (if_ar_lock),
        .axi_ar_cache_o   (if_ar_cache),
        .axi_ar_qos_o     (if_ar_qos),
        .axi_ar_region_o  (if_ar_region),

        .axi_r_ready_o    (if_r_ready),
        .axi_r_valid_i    (if_r_valid),
        .axi_r_resp_i     (if_r_resp),
        .axi_r_data_i     (if_r_data),
        .axi_r_last_i     (if_r_last),
        .axi_r_id_i       (if_r_id),
        .axi_r_user_i     (if_r_user)
    );

    wire                               mem_r_req;
    wire                               mem_r_handshaked;
    wire                               mem_r_okay;
    wire [`AXI_DATA_WIDTH-1:0]         mem_data_read;
    wire [`AXI_ADDR_WIDTH-1:0]         mem_r_addr;
    wire [ 1: 0]                       mem_r_size;
    wire [ 1: 0]                       mem_r_response;

    wire                               mem_w_req;
    wire                               mem_w_okay;
    wire [`AXI_DATA_WIDTH-1:0]         mem_data_write;
    wire [`AXI_ADDR_WIDTH-1:0]         mem_w_addr;
    wire [ 1: 0]                       mem_w_size;
    wire [ 1: 0]                       mem_w_response;

    wire                               mem_aw_ready;
    wire                               mem_aw_valid;
    wire [`AXI_ADDR_WIDTH-1:0]         mem_aw_addr;
    wire [ 2: 0]                       mem_aw_prot;
    wire [`AXI_ID_WIDTH-1:0]           mem_aw_id;
    wire [`AXI_USER_WIDTH-1:0]         mem_aw_user;
    wire [ 7: 0]                       mem_aw_len;
    wire [ 2: 0]                       mem_aw_size;
    wire [ 1: 0]                       mem_aw_burst;
    wire                               mem_aw_lock;
    wire [ 3: 0]                       mem_aw_cache;
    wire [ 3: 0]                       mem_aw_qos;
    wire [ 3: 0]                       mem_aw_region;
    wire                               mem_w_ready;
    wire                               mem_w_valid;
    wire [`AXI_DATA_WIDTH-1:0]         mem_w_data;
    wire [`AXI_DATA_WIDTH/8-1:0]       mem_w_strb;
    wire                               mem_w_last;
    wire [`AXI_USER_WIDTH-1:0]         mem_w_user;
    wire                               mem_b_ready;
    wire                               mem_b_valid;
    wire [ 1: 0]                       mem_b_resp;
    wire [`AXI_ID_WIDTH-1:0]           mem_b_id;
    wire [`AXI_USER_WIDTH-1:0]         mem_b_user;
    wire                               mem_ar_ready;
    wire                               mem_ar_valid;
    wire [`AXI_ADDR_WIDTH-1:0]         mem_ar_addr;
    wire [ 2: 0]                       mem_ar_prot;
    wire [`AXI_ID_WIDTH-1:0]           mem_ar_id;
    wire [`AXI_USER_WIDTH-1:0]         mem_ar_user;
    wire [ 7: 0]                       mem_ar_len;
    wire [ 2: 0]                       mem_ar_size;
    wire [ 1: 0]                       mem_ar_burst;
    wire                               mem_ar_lock;
    wire [ 3: 0]                       mem_ar_cache;
    wire [ 3: 0]                       mem_ar_qos;
    wire [ 3: 0]                       mem_ar_region;
    wire                               mem_r_ready;
    wire                               mem_r_valid;
    wire [ 1: 0]                       mem_r_resp;
    wire [`AXI_DATA_WIDTH-1:0]         mem_r_data;
    wire                               mem_r_last;
    wire [`AXI_ID_WIDTH-1:0]           mem_r_id;
    wire [`AXI_USER_WIDTH-1:0]         mem_r_user;

    axi_rw # (
        .AXI_ID(1)
    ) mem_axi_rw (
        .clock            (clock),
        .reset_n          (~reset),

        .r_req            (mem_r_req),
        .r_handshaked     (mem_r_handshaked),
        .r_okay           (mem_r_okay),
        .data_read        (mem_data_read),
        .r_addr           (mem_r_addr),
        .r_size           (mem_r_size),
        .r_resp           (mem_r_response),

        .w_req            (mem_w_req),
        .w_okay           (mem_w_okay),
        .data_write       (mem_data_write),
        .w_addr           (mem_w_addr),
        .w_size           (mem_w_size),
        .w_resp           (mem_w_response),

        .axi_aw_ready_i   (mem_aw_ready),
        .axi_aw_valid_o   (mem_aw_valid),
        .axi_aw_addr_o    (mem_aw_addr),
        .axi_aw_prot_o    (mem_aw_prot),
        .axi_aw_id_o      (mem_aw_id),
        .axi_aw_user_o    (mem_aw_user),
        .axi_aw_len_o     (mem_aw_len),
        .axi_aw_size_o    (mem_aw_size),
        .axi_aw_burst_o   (mem_aw_burst),
        .axi_aw_lock_o    (mem_aw_lock),
        .axi_aw_cache_o   (mem_aw_cache),
        .axi_aw_qos_o     (mem_aw_qos),
        .axi_aw_region_o  (mem_aw_region),

        .axi_w_ready_i    (mem_w_ready),
        .axi_w_valid_o    (mem_w_valid),
        .axi_w_data_o     (mem_w_data),
        .axi_w_strb_o     (mem_w_strb),
        .axi_w_last_o     (mem_w_last),
        .axi_w_user_o     (mem_w_user),

        .axi_b_ready_o    (mem_b_ready),
        .axi_b_valid_i    (mem_b_valid),
        .axi_b_resp_i     (mem_b_resp),
        .axi_b_id_i       (mem_b_id),
        .axi_b_user_i     (mem_b_user),

        .axi_ar_ready_i   (mem_ar_ready),
        .axi_ar_valid_o   (mem_ar_valid),
        .axi_ar_addr_o    (mem_ar_addr),
        .axi_ar_prot_o    (mem_ar_prot),
        .axi_ar_id_o      (mem_ar_id),
        .axi_ar_user_o    (mem_ar_user),
        .axi_ar_len_o     (mem_ar_len),
        .axi_ar_size_o    (mem_ar_size),
        .axi_ar_burst_o   (mem_ar_burst),
        .axi_ar_lock_o    (mem_ar_lock),
        .axi_ar_cache_o   (mem_ar_cache),
        .axi_ar_qos_o     (mem_ar_qos),
        .axi_ar_region_o  (mem_ar_region),

        .axi_r_ready_o    (mem_r_ready),
        .axi_r_valid_i    (mem_r_valid),
        .axi_r_resp_i     (mem_r_resp),
        .axi_r_data_i     (mem_r_data),
        .axi_r_last_i     (mem_r_last),
        .axi_r_id_i       (mem_r_id),
        .axi_r_user_i     (mem_r_user)
    );

    axi_interconnect axi_interconnect(
        .clock            (clock),
        .reset_n          (~reset),

        .if_aw_ready      (if_aw_ready),
        .if_aw_valid      (if_aw_valid),
        .if_aw_addr       (if_aw_addr),
        .if_aw_prot       (if_aw_prot),
        .if_aw_id         (if_aw_id),
        .if_aw_user       (if_aw_user),
        .if_aw_len        (if_aw_len),
        .if_aw_size       (if_aw_size),
        .if_aw_burst      (if_aw_burst),
        .if_aw_lock       (if_aw_lock),
        .if_aw_cache      (if_aw_cache),
        .if_aw_qos        (if_aw_qos),
        .if_aw_region     (if_aw_region),

        .if_w_ready       (if_w_ready),
        .if_w_valid       (if_w_valid),
        .if_w_data        (if_w_data),
        .if_w_strb        (if_w_strb),
        .if_w_last        (if_w_last),
        .if_w_user        (if_w_user),

        .if_b_ready       (if_b_ready),
        .if_b_valid       (if_b_valid),
        .if_b_resp        (if_b_resp),
        .if_b_id          (if_b_id),
        .if_b_user        (if_b_user),

        .if_ar_ready      (if_ar_ready),
        .if_ar_valid      (if_ar_valid),
        .if_ar_addr       (if_ar_addr),
        .if_ar_prot       (if_ar_prot),
        .if_ar_id         (if_ar_id),
        .if_ar_user       (if_ar_user),
        .if_ar_len        (if_ar_len),
        .if_ar_size       (if_ar_size),
        .if_ar_burst      (if_ar_burst),
        .if_ar_lock       (if_ar_lock),
        .if_ar_cache      (if_ar_cache),
        .if_ar_qos        (if_ar_qos),
        .if_ar_region     (if_ar_region),

        .if_r_ready       (if_r_ready),
        .if_r_valid       (if_r_valid),
        .if_r_resp        (if_r_resp),
        .if_r_data        (if_r_data),
        .if_r_last        (if_r_last),
        .if_r_id          (if_r_id),
        .if_r_user        (if_r_user),

        .mem_aw_ready     (mem_aw_ready),
        .mem_aw_valid     (mem_aw_valid),
        .mem_aw_addr      (mem_aw_addr),
        .mem_aw_prot      (mem_aw_prot),
        .mem_aw_id        (mem_aw_id),
        .mem_aw_user      (mem_aw_user),
        .mem_aw_len       (mem_aw_len),
        .mem_aw_size      (mem_aw_size),
        .mem_aw_burst     (mem_aw_burst),
        .mem_aw_lock      (mem_aw_lock),
        .mem_aw_cache     (mem_aw_cache),
        .mem_aw_qos       (mem_aw_qos),
        .mem_aw_region    (mem_aw_region),

        .mem_w_ready      (mem_w_ready),
        .mem_w_valid      (mem_w_valid),
        .mem_w_data       (mem_w_data),
        .mem_w_strb       (mem_w_strb),
        .mem_w_last       (mem_w_last),
        .mem_w_user       (mem_w_user),

        .mem_b_ready      (mem_b_ready),
        .mem_b_valid      (mem_b_valid),
        .mem_b_resp       (mem_b_resp),
        .mem_b_id         (mem_b_id),
        .mem_b_user       (mem_b_user),

        .mem_ar_ready     (mem_ar_ready),
        .mem_ar_valid     (mem_ar_valid),
        .mem_ar_addr      (mem_ar_addr),
        .mem_ar_prot      (mem_ar_prot),
        .mem_ar_id        (mem_ar_id),
        .mem_ar_user      (mem_ar_user),
        .mem_ar_len       (mem_ar_len),
        .mem_ar_size      (mem_ar_size),
        .mem_ar_burst     (mem_ar_burst),
        .mem_ar_lock      (mem_ar_lock),
        .mem_ar_cache     (mem_ar_cache),
        .mem_ar_qos       (mem_ar_qos),
        .mem_ar_region    (mem_ar_region),

        .mem_r_ready      (mem_r_ready),
        .mem_r_valid      (mem_r_valid),
        .mem_r_resp       (mem_r_resp),
        .mem_r_data       (mem_r_data),
        .mem_r_last       (mem_r_last),
        .mem_r_id         (mem_r_id),
        .mem_r_user       (mem_r_user),

        .clint_aw_ready   (clint_aw_ready),
        .clint_aw_valid   (clint_aw_valid),
        .clint_aw_addr    (clint_aw_addr),
        .clint_aw_prot    (clint_aw_prot),
        .clint_aw_id      (clint_aw_id),
        .clint_aw_user    (clint_aw_user),
        .clint_aw_len     (clint_aw_len),
        .clint_aw_size    (clint_aw_size),
        .clint_aw_burst   (clint_aw_burst),
        .clint_aw_lock    (clint_aw_lock),
        .clint_aw_cache   (clint_aw_cache),
        .clint_aw_qos     (clint_aw_qos),
        .clint_aw_region  (clint_aw_region),

        .clint_w_ready    (clint_w_ready),
        .clint_w_valid    (clint_w_valid),
        .clint_w_data     (clint_w_data),
        .clint_w_strb     (clint_w_strb),
        .clint_w_last     (clint_w_last),
        .clint_w_user     (clint_w_user),

        .clint_b_ready    (clint_b_ready),
        .clint_b_valid    (clint_b_valid),
        .clint_b_resp     (clint_b_resp),
        .clint_b_id       (clint_b_id),
        .clint_b_user     (clint_b_user),

        .clint_ar_ready   (clint_ar_ready),
        .clint_ar_valid   (clint_ar_valid),
        .clint_ar_addr    (clint_ar_addr),
        .clint_ar_prot    (clint_ar_prot),
        .clint_ar_id      (clint_ar_id),
        .clint_ar_user    (clint_ar_user),
        .clint_ar_len     (clint_ar_len),
        .clint_ar_size    (clint_ar_size),
        .clint_ar_burst   (clint_ar_burst),
        .clint_ar_lock    (clint_ar_lock),
        .clint_ar_cache   (clint_ar_cache),
        .clint_ar_qos     (clint_ar_qos),
        .clint_ar_region  (clint_ar_region),

        .clint_r_ready    (clint_r_ready),
        .clint_r_valid    (clint_r_valid),
        .clint_r_resp     (clint_r_resp),
        .clint_r_data     (clint_r_data),
        .clint_r_last     (clint_r_last),
        .clint_r_id       (clint_r_id),
        .clint_r_user     (clint_r_user),

        .axi_aw_ready     (axi_aw_ready),
        .axi_aw_valid     (axi_aw_valid),
        .axi_aw_addr      (axi_aw_addr),
        .axi_aw_prot      (axi_aw_prot),
        .axi_aw_id        (axi_aw_id),
        .axi_aw_user      (axi_aw_user),
        .axi_aw_len       (axi_aw_len),
        .axi_aw_size      (axi_aw_size),
        .axi_aw_burst     (axi_aw_burst),
        .axi_aw_lock      (axi_aw_lock),
        .axi_aw_cache     (axi_aw_cache),
        .axi_aw_qos       (axi_aw_qos),
        .axi_aw_region    (axi_aw_region),

        .axi_w_ready      (axi_w_ready),
        .axi_w_valid      (axi_w_valid),
        .axi_w_data       (axi_w_data),
        .axi_w_strb       (axi_w_strb),
        .axi_w_last       (axi_w_last),
        .axi_w_user       (axi_w_user),

        .axi_b_ready      (axi_b_ready),
        .axi_b_valid      (axi_b_valid),
        .axi_b_resp       (axi_b_resp),
        .axi_b_id         (axi_b_id),
        .axi_b_user       (axi_b_user),

        .axi_ar_ready     (axi_ar_ready),
        .axi_ar_valid     (axi_ar_valid),
        .axi_ar_addr      (axi_ar_addr),
        .axi_ar_prot      (axi_ar_prot),
        .axi_ar_id        (axi_ar_id),
        .axi_ar_user      (axi_ar_user),
        .axi_ar_len       (axi_ar_len),
        .axi_ar_size      (axi_ar_size),
        .axi_ar_burst     (axi_ar_burst),
        .axi_ar_lock      (axi_ar_lock),
        .axi_ar_cache     (axi_ar_cache),
        .axi_ar_qos       (axi_ar_qos),
        .axi_ar_region    (axi_ar_region),

        .axi_r_ready      (axi_r_ready),
        .axi_r_valid      (axi_r_valid),
        .axi_r_resp       (axi_r_resp),
        .axi_r_data       (axi_r_data),
        .axi_r_last       (axi_r_last),
        .axi_r_id         (axi_r_id),
        .axi_r_user       (axi_r_user)
    );

endmodule